package yxk.service.configm;

import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.logging.Log;
import kd.bos.logging.LogFactory;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import kd.sdk.wtc.wtes.business.tie.core.chain.TieContextExt;
import kd.sdk.wtc.wtes.business.tie.exexutor.att.AttEvaluatorExpService;
import kd.sdk.wtc.wtes.business.tie.exexutor.att.OnEvaluateAttendanceEndEvent;
import kd.sdk.wtc.wtes.business.tie.model.attitem.AttItemInstanceExt;
import kd.sdk.wtc.wtes.business.tie.model.attitem.AttItemSpecExt;
import kd.sdk.wtc.wtes.business.tie.model.roster.RosterExt;
import kd.sdk.wtc.wtes.business.tie.model.roster.ShiftSpecExt;
import kd.sdk.wtc.wtes.business.tie.model.timebucket.TimeBucketExt;
import kd.sdk.wtc.wtpm.business.punchcard.WTPMPunchCardHelper;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.*;
import java.util.*;

/**
 * 夜班小时数计算
 * 早班小时计算
 */
public class AttEvaluatorExpServiceImp implements AttEvaluatorExpService {
    SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
    SimpleDateFormat forma = new SimpleDateFormat("yyyy-MM-dd HH:mm");

    private static final Log LOG = LogFactory.getLog(AttEvaluatorExpServiceImp.class);
    @Override
    public void onEvaluateAttendanceEnd(OnEvaluateAttendanceEndEvent event) {
        //获取核算人上下文
        TieContextExt tieContextExt = event.getTieContextExt();
        LocalDate calculateDate = tieContextExt.getCalculateDate();
        LOG.info("AttEvaluatorExpServiceImp.onEvaluateAttendanceEnd.tieContextExt:{},calculateDate:{}",tieContextExt,calculateDate);

        //是否计算夜班时长
        Boolean nightBool=true;
        //是否计算早班时长
        Boolean earlyBool=true;
        // 获取当日班次
        long attPersonId = tieContextExt.getAttPersonId();
        Map<String, LocalDateTime> stringLocalDateTimeMap = parseCardDetail(attPersonId, calculateDate.toString());
        if(stringLocalDateTimeMap == null){
            return;
        }
        LocalDateTime start = stringLocalDateTimeMap.get("start");
        LocalDateTime end = stringLocalDateTimeMap.get("end");
        Long time = getCountLocaDateTime(calculateDate, start, end);
        if(time == 0L){
            nightBool=false;
        }
        Long earlyLocaDateTime = getEarlyLocaDateTime(calculateDate, start, end);
        if(earlyLocaDateTime == 0L){
            earlyBool=false;
        }
        RosterExt rosterExt = tieContextExt.getRosterExt(calculateDate);
        ShiftSpecExt shiftSpec = rosterExt.getShiftSpec();

        QFilter qF01 = new QFilter("number", QCP.equals, "1001_S");
        qF01.and("iscurrentversion", QCP.equals,'1')
                .and("enable", QCP.equals,'1')
                .and("datastatus", QCP.equals,'1');
        //夜班时长考勤项目的ID
        DynamicObject single = BusinessDataServiceHelper.loadSingle("wtbd_attitem","id", qF01.toArray());
        long bid = single.getLong("id");
        AttItemSpecExt attItemSpecExt = tieContextExt.getAttItemSpecExt(bid, calculateDate);
        //早班时长考勤项目的ID
        QFilter qF02 = new QFilter("number", QCP.equals, "1002_S");
        qF01.and("iscurrentversion", QCP.equals,'1')
                .and("enable", QCP.equals,'1')
                .and("datastatus", QCP.equals,'1');
        DynamicObject early = BusinessDataServiceHelper.loadSingle("wtbd_attitem","id",qF02.toArray());
        long earlyId = early.getLong("id");
        AttItemSpecExt specExt = tieContextExt.getAttItemSpecExt(earlyId, calculateDate);

        List<TimeBucketExt> timeBucketExtList = event.getTimeBucketExtList();
        List<AttItemInstanceExt> itemInstanceExtList = new ArrayList<>();
        //有效卡为空生成0时考勤项目
        if(timeBucketExtList == null || timeBucketExtList.size() == 0){
            //早班时长项目
            AttItemInstanceExt ext = new AttItemInstanceExt(specExt, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
            itemInstanceExtList.add(ext);
            //晚班时长项目
            AttItemInstanceExt instanceExt = new AttItemInstanceExt(attItemSpecExt, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
            itemInstanceExtList.add(instanceExt);

        }else {
            for (TimeBucketExt timeBucketExt : timeBucketExtList) {
                //获取有效卡开始时间和结束时间
                LocalDateTime startTime = timeBucketExt.getStartTime();
                LocalDateTime endTime = timeBucketExt.getEndTime();
                //计算夜班时长
                if(nightBool) {
                    Long millis;
                    if(end.compareTo(endTime) == 1){
                        if(startTime.compareTo(start)== 1){
                            millis = getCountLocaDateTime(calculateDate, startTime, endTime);
                        }else {
                            millis = getCountLocaDateTime(calculateDate, start, endTime);
                        }

                    }else{
                        if(startTime.compareTo(start)== 1){
                            millis = getCountLocaDateTime(calculateDate, startTime, end);
                        }else {
                            millis = getCountLocaDateTime(calculateDate, start, end);
                        }

                    }
                    BigDecimal secondDecimal = BigDecimal.valueOf(millis / 1000.0d).setScale(6, RoundingMode.HALF_UP);
                    BigDecimal dayDecimal = shiftSpec.secondsToDays(secondDecimal);
                    AttItemInstanceExt instanceExt = new AttItemInstanceExt(attItemSpecExt, secondDecimal, dayDecimal, secondDecimal);
                    itemInstanceExtList.add(instanceExt);
                }
                //计算早班时长
                if(earlyBool){
                    Long millis;
                    if(start.compareTo(startTime) == 1){
                        if(end.compareTo(endTime) == 1){
                            millis = getEarlyLocaDateTime(calculateDate, start, end);
                        }else{
                            millis = getEarlyLocaDateTime(calculateDate, start, endTime);
                        }
                    }else {
                        if(end.compareTo(endTime) == 1){
                            millis = getEarlyLocaDateTime(calculateDate, startTime, end);
                        }else{
                            millis = getEarlyLocaDateTime(calculateDate, startTime, endTime);
                        }
                    }
                    BigDecimal secondDecimal = BigDecimal.valueOf(millis / 1000.0d).setScale(6, RoundingMode.HALF_UP);
                    BigDecimal dayDecimal = shiftSpec.secondsToDays(secondDecimal);
                    AttItemInstanceExt instanceExt = new AttItemInstanceExt(specExt, secondDecimal, dayDecimal, secondDecimal);
                    itemInstanceExtList.add(instanceExt);
                }
            }
        }
        event.setAttItemSpecExtList(itemInstanceExtList);
    }

    /**计算 当日20到次日08工作时长
     * @param startTime     有效卡开始时间
     * @param endTime       有效卡结束时间
     * @return              计算开始时间、结束时间 用于计算时长
     */
    private Long getCountLocaDateTime( LocalDate calDate,LocalDateTime startTime,LocalDateTime endTime){
        LocalDateTime start=null;
        LocalDateTime end=null;
        //获取当日期0点
        LocalDateTime dateTime = calDate.atStartOfDay();
        ////获取当日20点
        LocalDateTime startDateTime = dateTime.withHour(20);
        //获取次日8点
        LocalDateTime entDateTime = dateTime.plusDays(1).withHour(8);
        /**
         * 场景1 12/23 09:00 - 12/23 18:00    结束时间为20点之前 不计算夜班时长
         * 场景2 12/23 14:00 - 12/23 22:00    开始时间为20点之前 结束时间为20点之后 且 结束时间为次日8点之前 计算夜班时长
         * 场景3 12/23 14:00 - 12/23 22:00    开始时间为20点之前 结束时间为20点之后 且 结束时间为次日8点之后 计算夜班时长
         * 场景4 12/23 20:00 - 12/24 08:00    开始、结束时间为20点之后 计算夜班时长
         * startTime.compareTo(startDate) = 1 为 startTime 大于 startDate
         * startTime.compareTo(startDate) = 0 为 startTime 等于 startDate
         * startTime.compareTo(startDate) = -1 为 startTime 小于 startDate
         */
            //场景1 12/23 09:00 - 12/23 18:00    结束时间为20点之前 不计算夜班时长
           if(endTime.compareTo(startDateTime) == -1){
               return 0L;
           }else
               //场景2 12/23 14:00 - 12/23 22:00    开始时间为20点之前 结束时间为20点之后 计算夜班时长
           if(startTime.compareTo(startDateTime) == -1 && endTime.compareTo(startDateTime) == 1){
               start=startDateTime;
               //判断结束时间为次日8点之后
               if(endTime.compareTo(entDateTime) >= 0) {
                   end=entDateTime;
               }else{
                   end = endTime;
               }
               return Duration.between(start, end).toMillis();
           } else
               //场景4 12/23 20:00 - 12/24 08:00    开始为20点之后 计算夜班时长
           if(startTime.compareTo(startDateTime) >= 0 ) {
               start=startTime;
               //判断结束时间为次日8点之后
               if(endTime.compareTo(entDateTime) >= 0) {
                   end=entDateTime;
               }else{
                   end = endTime;
               }
               return Duration.between(start, end).toMillis();
           }

        return 0L;
    }

    /**计算 当日0点到当日08工作时长
     * @param startTime     有效卡开始时间
     * @param endTime       有效卡结束时间
     * @return              计算开始时间、结束时间 用于计算时长
     */
    private Long getEarlyLocaDateTime(LocalDate calDate,LocalDateTime startTime,LocalDateTime endTime){
        LocalDateTime start=null;
        LocalDateTime end=null;
        //获取当日期0点
        LocalDateTime dateTime = calDate.atStartOfDay();
        ////获取当日08点
        LocalDateTime endDateTime = dateTime.withHour(8);
        /**
         * 场景1   12/23 09:00 - 12/23 18:00    开始时间为8点之后 不计算早班时长
         * 场景2   12/23 03:00 - 12/23 07:00    开始时间为0点之后，结束时间为08之前 不计算早班时长
         * startTime.compareTo(startDate) = 1 为 startTime 大于 startDate
         * startTime.compareTo(startDate) = 0 为 startTime 等于 startDate
         * startTime.compareTo(startDate) = -1 为 startTime 小于 startDate
         */
        if(startTime.compareTo(dateTime) == 1 && startTime.compareTo(endDateTime) == -1 ){
            start=startTime;
            //判断结束时间为8点之后
            if(endTime.compareTo(endDateTime) >= 0) {
                end=endDateTime;
            }else{
                end = endTime;
            }
            return Duration.between(start, end).toMillis();
        }

        return 0L;
    }


    /***
     * 获取班次开始时间和结束时间
     * @param signPersonId
     * @param date
     * @return
     */
    public Map<String, LocalDateTime> parseCardDetail(Long signPersonId,String date){
        Map<String,LocalDateTime> map=new HashMap<>();
       // String format = formatter.format(date);
        //班次开始时间
        Date start=null;
        //班次结束时间
        Date end=null;
        try {
            Map<Date, Map<String, Object>> punchCardDetail = WTPMPunchCardHelper.getPunchCardDetail(signPersonId,formatter.parse(date) , formatter.parse(date) );
            LOG.info("BusitripseServiceMethod.punchCardDetail:{}",punchCardDetail);
            Set<Map.Entry<Date, Map<String, Object>>> entries = punchCardDetail.entrySet();
            for (Map.Entry<Date, Map<String, Object>> entry : entries) {
                Map<String, Object> value = entry.getValue();
                LOG.info("BusitripseServiceMethod.parseCardDetail.value:{}",value);
                Object offshift = value.get("offshift");
                Boolean off = offshift instanceof String?"true".equals(offshift.toString())?true:false :
                        Boolean.TRUE.equals(offshift)?true:false;
                if(off){
                    return null;
                }
                List<Map<String,String>> listMap= (List<Map<String,String>>) value.get("shift");
                LOG.info("BusitripseServiceMethod.parseCardDetail.listMap:{}",listMap);
                for (Map<String, String> row:listMap) {
                    Date startTime = forma.parse(row.get("start"));
                    if(start == null){
                        start = startTime;
                    }else {
                        start =  start.getTime() < startTime.getTime()? start : startTime;
                    }
                    Date endTime = forma.parse(row.get("end"));
                    if(end == null){
                        end=endTime;
                    }else {
                        end =  end.getTime() < endTime.getTime()? endTime : end;
                    }
                }
            }
            LocalDateTime startDateTime = LocalDateTime.ofInstant(start.toInstant(), ZoneId.systemDefault());
            LocalDateTime endDateTime = LocalDateTime.ofInstant(end.toInstant(), ZoneId.systemDefault());
            map.put("start",startDateTime);
            map.put("end",endDateTime);

        }catch (Exception e){
            LOG.info("BusitripseServiceMethod.parseCardDetail:{}，e:{}","获取班次服务错误",e);
        }
        return map;
    }
}
